package com.ruoyi.collect.service.impl;

import com.ruoyi.collect.domain.CollectBind;
import com.ruoyi.collect.domain.CollectSite;
import com.ruoyi.collect.domain.CollectTask;
import com.ruoyi.collect.engine.client.MacCmsApiClient;
import com.ruoyi.collect.engine.client.MacCmsRequest;
import com.ruoyi.collect.engine.client.MacCmsResponse;
import com.ruoyi.collect.engine.transformer.DataTransformer;
import com.ruoyi.collect.service.ICollectBindService;
import com.ruoyi.collect.service.ICollectEngineService;
import com.ruoyi.collect.service.ICollectSiteService;
import com.ruoyi.collect.service.ICollectTaskService;
import com.ruoyi.collect.service.IDataDictionaryService;
import com.ruoyi.collect.utils.ImageLocalizer;
import com.ruoyi.collect.utils.DataDeduplicator;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.movie.domain.MovieBasics;
import com.ruoyi.movie.domain.VideoResource;
import com.ruoyi.movie.service.IMovieBasicsService;
import com.ruoyi.movie.service.IVideoResourceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 采集引擎服务实现类
 *
 * @author ruoyi
 * @date 2025-11-07
 */
@Service
public class CollectEngineServiceImpl implements ICollectEngineService {

    private static final Logger log = LoggerFactory.getLogger(CollectEngineServiceImpl.class);

    @Autowired
    private ICollectSiteService collectSiteService;

    @Autowired
    private ICollectBindService collectBindService;

    @Autowired
    private ICollectTaskService collectTaskService;

    @Autowired
    private IMovieBasicsService movieBasicsService;

    @Autowired
    private IVideoResourceService videoResourceService;

    @Autowired
    private MacCmsApiClient macCmsApiClient;

    @Autowired
    private DataTransformer dataTransformer;

    @Autowired
    private ImageLocalizer imageLocalizer;

    @Autowired
    private DataDeduplicator dataDeduplicator;

    @Autowired
    private IDataDictionaryService dataDictionaryService;

    // 任务执行状态映射
    private final Map<Long, Boolean> runningTasks = new ConcurrentHashMap<>();

    /**
     * 视频处理结果（用于批量操作）
     */
    private static class ProcessResult {
        MovieBasics movie;
        List<VideoResource> resources;
        boolean isNew;  // true=新增, false=更新
        boolean skip;   // 是否跳过

        ProcessResult(MovieBasics movie, List<VideoResource> resources, boolean isNew) {
            this.movie = movie;
            this.resources = resources;
            this.isNew = isNew;
            this.skip = false;
        }

        ProcessResult(boolean skip) {
            this.skip = skip;
        }
    }

    /**
     * 执行采集任务
     *
     * @param taskId 任务ID
     * @return 如果执行成功启动返回true
     * 注意: 此方法不使用@Transactional，因为：
     *   1. 采集是长时间运行的任务，不适合放在一个大事务中
     *   2. 每个视频的处理在processVod中有独立的事务管理
     *   3. @Transactional会导致@Async异步失效，造成接口超时
     */
    @Override
    public boolean executeTask(Long taskId) {
        try {
            CollectTask task = collectTaskService.selectCollectTaskById(taskId);
            if (task == null) {
                log.error("任务不存在: {}", taskId);
                return false;
            }

            if (runningTasks.containsKey(taskId)) {
                log.warn("任务 {} 已经在运行中", taskId);
                return false;
            }

            CollectSite site = collectSiteService.selectCollectSiteById(task.getSiteId());
            if (site == null) {
                log.error("站点不存在，任务: {}", taskId);
                collectTaskService.failTask(taskId, "站点不存在");
                return false;
            }

            // 标记任务为运行中
            runningTasks.put(taskId, true);
            collectTaskService.updateTaskStatus(taskId, "1"); // 运行中

            // 【新增】获取已绑定的类型ID集合（用于过滤）
          //  java.util.Set<String> boundTypeIds = collectBindService.getBoundSourceTypeIds(site.getSiteId());
            // 获取类型绑定映射
            Map<String, CollectBind> bindMap = collectBindService.getBindingMap(site.getSiteId());
            if (bindMap.size() == 0) {
                log.warn("站点 {} 未配置任何类型绑定，跳过采集", site.getSiteName());
                collectTaskService.failTask(taskId, "未配置类型绑定");
                return false;
            }


            log.info("站点 {} 已绑定 {} 个分类: {}", site.getSiteName(), bindMap.size(), bindMap.keySet());



            // 构建请求
            MacCmsRequest request = buildRequest(task, site);

            int successCount = 0;
            int failureCount = 0;
            int skippedCount = 0; // 【新增】跳过数量统计
            int currentPage = task.getCurrentPage() != null ? task.getCurrentPage() : 1;
            int totalPages = 0;

            // 获取最大采集页数限制
            Integer maxCollectPages = site.getMaxCollectPages();
            // 初始化页数上限：如果未配置或配置为0，则不限制（使用一个很大的值作为安全限制）
            int maxPageLimit = (maxCollectPages == null || maxCollectPages <= 0) ? 10000 : maxCollectPages;
            boolean useTotalPagesFromApi = false; // 标记是否已从API获取到总页数

            log.info("开始采集任务 {}，初始最大页数限制: {}", taskId,
                maxCollectPages == null || maxCollectPages <= 0 ? "不限制" : maxCollectPages);

            try {
                // 采集循环
                while (runningTasks.get(taskId)) {
                    request.setPg(currentPage);

                    log.info("正在采集第 {} 页，任务 {}，数据格式: {}", currentPage, taskId,
                        site.getDataFormat() == null ? "自动" :
                        ("0".equals(site.getDataFormat()) ? "自动" :
                         ("1".equals(site.getDataFormat()) ? "XML" : "JSON")));

                    // 根据站点配置的dataFormat调用相应的方法
                    MacCmsResponse response = macCmsApiClient.getList(site.getSiteUrl(), request, site.getDataFormat());

                    if (response == null || response.getList() == null) {
                        log.warn("第 {} 页没有接收到数据", currentPage);
                        break;
                    }

                    // 更新总页数（从API响应中获取）
                    if (response.getPage() != null && response.getPage().getPagecount() != null) {
                        totalPages = response.getPage().getPagecount();

                        // 【修复】首次获取到API总页数时，更新实际采集上限
                        if (!useTotalPagesFromApi && totalPages > 0) {
                            useTotalPagesFromApi = true;
                            // 使用API返回的总页数作为实际上限，但保留10000的安全限制
                            maxPageLimit = Math.min(totalPages, 10000);
                            log.info("从API获取到总页数: {}, 更新采集上限为: {} (忽略站点配置的maxCollectPages={})",
                                totalPages, maxPageLimit, maxCollectPages);
                        }

                        log.debug("当前进度: {}/{}, 采集上限: {}",
                            currentPage, totalPages, maxPageLimit);
                    }

                    // 【优化】批量预查询：一次性查询当前页所有视频的采集ID
                    Map<String, MovieBasics> existingMoviesMap = batchQueryExistingMovies(
                        response.getList(), site.getSiteFlag());

                    // 收集处理结果
                    List<ProcessResult> processResults = new ArrayList<>();

                    // 处理每个视频（不直接操作数据库）
                    for (MacCmsResponse.VodInfo vod : response.getList()) {
                        // 【新增】类型过滤
                        if (!bindMap.containsKey(vod.getTypeId())) {
                            log.debug("跳过未绑定类型的视频: {} (type_id={})",
                                vod.getVodName(), vod.getTypeId());
                            skippedCount++;
                            continue;
                        }

                        try {
                            ProcessResult result = prepareVodData(vod, site, task, bindMap, existingMoviesMap);
                            if (!result.skip) {
                                processResults.add(result);
                            }
                        } catch (Exception e) {
                            log.error("处理视频失败: {}", e.getMessage());
                            failureCount++;
                        }
                    }

                    // 【优化】批量执行数据库操作
                    int batchSuccess = batchSaveMovies(processResults);
                    successCount += batchSuccess;
                    failureCount += (processResults.size() - batchSuccess);

                    // 更新进度
                    collectTaskService.updateTaskProgress(taskId, currentPage, totalPages,
                            successCount + failureCount);

                    // 检查是否继续采集
                    // 1. 检查是否已达到API返回的实际总页数
                    if (totalPages > 0 && currentPage >= totalPages) {
                        log.info("已采集到最后一页 (页码: {}/{}), 结束采集", currentPage, totalPages);
                        break;
                    }

                    // 2. 检查是否已达到采集页数上限（已动态更新为totalPages或配置限制）
                    if (currentPage >= maxPageLimit) {
                        if (useTotalPagesFromApi) {
                            log.info("已采集到API总页数上限 ({}页), 结束采集", maxPageLimit);
                        } else {
                            log.info("已达到最大采集页数限制 ({}页，站点配置), 结束采集", maxPageLimit);
                        }
                        break;
                    }

                    // 3. 检查是否还有更多数据（本页数据量少于每页数量）
                    if (response.getList().size() < (request.getPagesize() != null ? request.getPagesize() : 20)) {
                        log.info("本页数据量 ({}) 少于每页数量, 判断为无更多数据, 结束采集", response.getList().size());
                        break;
                    }

                    currentPage++;

                    // 短暂延迟以避免压垮远程服务器
                    Thread.sleep(500);
                }

                // 标记任务为已完成
                collectTaskService.completeTask(taskId, successCount, failureCount);
                log.info("任务 {} 完成。采集页数: {}{}, 成功: {}, 失败: {}, 跳过（未绑定类型）: {}",
                    taskId, currentPage,
                    totalPages > 0 ? "/" + totalPages : "",
                    successCount, failureCount, skippedCount);
                return true;

            } catch (Exception e) {
                log.error("任务执行失败: {}", e.getMessage(), e);
                collectTaskService.failTask(taskId, e.getMessage());
                return false;
            }

        } finally {
            runningTasks.remove(taskId);
        }
    }

    /**
     * 异步执行采集任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Async
    public void executeTaskAsync(Long taskId) {
        executeTask(taskId);
    }

    /**
     * 处理单个视频项
     */
    private void processVod(MacCmsResponse.VodInfo vod, CollectSite site, CollectTask task,
                            Map<String, CollectBind> bindMap) {
        // 转换为MovieBasics
        MovieBasics movie = dataTransformer.transformToMovieBasics(vod, task, bindMap);

        // 数据验证
        if (!dataDeduplicator.isValidMovie(movie)) {
            log.warn("无效的影视数据，跳过: {}", movie.getTitle());
            return;
        }

        // 图片本地化处理
        if ("1".equals(site.getPicMode()) && StringUtils.isNotEmpty(movie.getPoster())) {
            String localPath = imageLocalizer.downloadImage(movie.getPoster());
            movie.setPoster(localPath);
        }

        // 检查是否存在
        MovieBasics existing = movieBasicsService.selectMovieByCollectId(
                site.getSiteFlag(), vod.getVodId());

        if (existing != null) {
            // 检查是否需要更新
            if (dataTransformer.needsUpdate(existing, vod, site.getUprule())) {
                // 图片本地化后再合并
                dataTransformer.mergeMovieData(existing, movie, site.getUprule());
                movieBasicsService.updateMovieBasics(existing);

                // 提取并保存基础数据字典（国家、演员、语言等）
                dataDictionaryService.extractAndSaveDictionaries(existing);

                // 更新视频资源
                updateVideoResources(existing.getMovieBasicsId(), vod, site.getUprule());
            }
        } else {
            // 去重检查（基于标题+年份）
            MovieBasics duplicate = findDuplicateMovie(movie);
            if (duplicate != null) {
                log.info("发现重复影视: {} (ID: {}), 跳过采集", movie.getTitle(), duplicate.getMovieBasicsId());
                return;
            }

            // 插入新影视
            movieBasicsService.insertMovieBasics(movie);

            // 提取并保存基础数据字典（国家、演员、语言等）
            dataDictionaryService.extractAndSaveDictionaries(movie);

            // 批量插入视频资源
            List<VideoResource> resources = dataTransformer.transformToVideoResources(
                    vod, movie.getMovieBasicsId());
            if (!resources.isEmpty()) {
                videoResourceService.batchInsertVideoResource(resources);
            }
        }
    }

    /**
     * 查找重复的影视
     *
     * @param movie 影视信息
     * @return 重复的影视，如果不存在返回null
     */
    private MovieBasics findDuplicateMovie(MovieBasics movie) {
        // 根据标题和年份查询
        MovieBasics query = new MovieBasics();
        query.setTitle(movie.getTitle());
        query.setYear(movie.getYear());
        List<MovieBasics> candidates = movieBasicsService.selectMovieBasicsList(query);

        if (candidates == null || candidates.isEmpty()) {
            return null;
        }

        // 使用去重工具进行精确匹配
        for (MovieBasics candidate : candidates) {
            if (dataDeduplicator.isDuplicate(movie, candidate)) {
                return candidate;
            }
        }

        return null;
    }

    /**
     * 更新现有影视的视频资源
     */
    private void updateVideoResources(Integer movieId, MacCmsResponse.VodInfo vod, String uprule) {
        List<VideoResource> existingResources = videoResourceService.selectVideoResourceListByMovieId(movieId);
        List<VideoResource> newResources = dataTransformer.transformToVideoResources(vod, movieId);

        List<VideoResource> mergedResources = dataTransformer.mergeVideoResources(
                existingResources, newResources, uprule);

        // 删除该影视的所有旧资源（一次性删除）
        if (!existingResources.isEmpty()) {
            videoResourceService.deleteVideoResourceListByMovieId(movieId);
        }

        // 批量插入合并后的资源
        if (!mergedResources.isEmpty()) {
            // 清除ID以进行新插入
            for (VideoResource resource : mergedResources) {
                resource.setResourceId(null);
            }
            videoResourceService.batchInsertVideoResource(mergedResources);
        }
    }

    /**
     * 从任务参数构建请求
     *
     * @param task 采集任务
     * @param site 采集站点
     * @return MacCMS API请求对象
     */
    private MacCmsRequest buildRequest(CollectTask task, CollectSite site) {
        MacCmsRequest request = new MacCmsRequest();

        // 根据resource_type和collect_type动态设置ac参数
        String collectType = task.getCollectType();
        String resourceType = site.getResourceType();

        if ("list".equals(collectType)) {
            // 列表采集
            if ("1".equals(resourceType)) {
                // 视频资源使用videolist（MacCMS v10推荐）
                request.setAc("videolist");
                log.debug("视频资源列表采集，使用ac=videolist");
            } else {
                // 文章、演员等其他资源使用list
                request.setAc("list");
                log.debug("非视频资源列表采集（type={}），使用ac=list", resourceType);
            }
        } else if ("detail".equals(collectType)) {
            // 详情采集保持使用detail
            request.setAc("detail");
            log.debug("详情采集，使用ac=detail");
        } else {
            // 其他类型直接使用任务指定的collect_type
            request.setAc(collectType);
            log.debug("使用任务指定的ac参数: {}", collectType);
        }

        if (StringUtils.isNotEmpty(task.getTypeFilter())) {
            request.setT(Integer.parseInt(task.getTypeFilter()));
        }

        if (task.getHours() != null && task.getHours() > 0) {
            request.setH(task.getHours());
        }

        if (StringUtils.isNotEmpty(task.getIds())) {
            request.setIds(task.getIds());
        }

        if (StringUtils.isNotEmpty(task.getKeyword())) {
            request.setWd(task.getKeyword());
        }

        return request;
    }

    /**
     * 采集站点所有数据
     */
    @Override
    public CollectTask collectAll(Long siteId) {
        CollectSite site = collectSiteService.selectCollectSiteById(siteId);
        if (site == null) {
            log.error("站点不存在: {}", siteId);
            return null;
        }

        CollectTask task = new CollectTask();
        task.setSiteId(siteId);
        task.setSiteName(site.getSiteName());
        task.setSiteUrl(site.getSiteUrl());
        task.setSiteFlag(site.getSiteFlag());
        task.setTaskName("采集全部 - " + site.getSiteName());
        task.setCollectType("list");
        task.setTaskType("0"); // 手动

        collectTaskService.insertCollectTask(task);
        executeTaskAsync(task.getTaskId());
        return task;
    }

    /**
     * 采集站点最新数据
     */
    @Override
    public CollectTask collectRecent(Long siteId, Integer hours) {
        CollectSite site = collectSiteService.selectCollectSiteById(siteId);
        if (site == null) {
            log.error("站点不存在: {}", siteId);
            return null;
        }

        CollectTask task = new CollectTask();
        task.setSiteId(siteId);
        task.setSiteName(site.getSiteName());
        task.setSiteUrl(site.getSiteUrl());
        task.setSiteFlag(site.getSiteFlag());
        task.setTaskName("采集最近 " + hours + " 小时 - " + site.getSiteName());
        task.setCollectType("list");
        task.setHours(hours);
        task.setTaskType("0"); // 手动

        collectTaskService.insertCollectTask(task);
        executeTaskAsync(task.getTaskId());
        return task;
    }

    /**
     * 按类型采集站点数据
     */
    @Override
    public CollectTask collectByType(Long siteId, String typeId) {
        CollectSite site = collectSiteService.selectCollectSiteById(siteId);
        if (site == null) {
            log.error("站点不存在: {}", siteId);
            return null;
        }

        CollectTask task = new CollectTask();
        task.setSiteId(siteId);
        task.setSiteName(site.getSiteName());
        task.setSiteUrl(site.getSiteUrl());
        task.setSiteFlag(site.getSiteFlag());
        task.setTaskName("采集类型 " + typeId + " - " + site.getSiteName());
        task.setCollectType("list");
        task.setTypeFilter(typeId);
        task.setTaskType("0"); // 手动

        collectTaskService.insertCollectTask(task);
        executeTaskAsync(task.getTaskId());
        return task;
    }

    /**
     * 按ID采集站点数据
     */
    @Override
    public CollectTask collectByIds(Long siteId, String ids) {
        CollectSite site = collectSiteService.selectCollectSiteById(siteId);
        if (site == null) {
            log.error("站点不存在: {}", siteId);
            return null;
        }

        CollectTask task = new CollectTask();
        task.setSiteId(siteId);
        task.setSiteName(site.getSiteName());
        task.setSiteUrl(site.getSiteUrl());
        task.setSiteFlag(site.getSiteFlag());
        task.setTaskName("采集指定ID - " + site.getSiteName());
        task.setCollectType("detail");
        task.setIds(ids);
        task.setTaskType("0"); // 手动

        collectTaskService.insertCollectTask(task);
        executeTaskAsync(task.getTaskId());
        return task;
    }

    /**
     * 停止运行中的任务
     */
    @Override
    public boolean stopTask(Long taskId) {
        if (runningTasks.containsKey(taskId)) {
            runningTasks.put(taskId, false);
            collectTaskService.updateTaskStatus(taskId, "4"); // 已停止
            return true;
        }
        return false;
    }

    /**
     * 暂停运行中的任务
     */
    @Override
    public boolean pauseTask(Long taskId) {
        if (runningTasks.containsKey(taskId)) {
            runningTasks.put(taskId, false);
            collectTaskService.updateTaskStatus(taskId, "5"); // 已暂停
            return true;
        }
        return false;
    }

    /**
     * 恢复暂停的任务
     */
    @Override
    public boolean resumeTask(Long taskId) {
        CollectTask task = collectTaskService.selectCollectTaskById(taskId);
        if (task != null && "5".equals(task.getTaskStatus())) {
            executeTaskAsync(taskId);
            return true;
        }
        return false;
    }

    /**
     * 获取任务执行状态
     */
    @Override
    public String getTaskStatus(Long taskId) {
        CollectTask task = collectTaskService.selectCollectTaskById(taskId);
        if (task == null) {
            return "任务不存在";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("状态: ").append(getStatusName(task.getTaskStatus()));
        if (task.getProgress() != null) {
            sb.append(", 进度: ").append(task.getProgress()).append("%");
        }
        if (task.getCurrentPage() != null && task.getTotalPages() != null) {
            sb.append(", 页码: ").append(task.getCurrentPage()).append("/").append(task.getTotalPages());
        }
        if (task.getCollectedCount() != null) {
            sb.append(", 已采集: ").append(task.getCollectedCount());
        }

        return sb.toString();
    }

    private String getStatusName(String status) {
        switch (status) {
            case "0": return "待执行";
            case "1": return "执行中";
            case "2": return "已完成";
            case "3": return "失败";
            case "4": return "已停止";
            case "5": return "已暂停";
            default: return "未知";
        }
    }

    /**
     * 测试站点采集
     */
    @Override
    public String testCollection(Long siteId, Integer limit) {
        try {
            CollectSite site = collectSiteService.selectCollectSiteById(siteId);
            if (site == null) {
                return "站点不存在";
            }

            MacCmsRequest request = new MacCmsRequest();
            request.setAc("list");
            request.setPg(1);
            request.setPagesize(limit != null ? limit : 5);

            log.info("测试采集站点: {}, 数据格式: {}", site.getSiteName(),
                site.getDataFormat() == null ? "自动" :
                ("0".equals(site.getDataFormat()) ? "自动" :
                 ("1".equals(site.getDataFormat()) ? "XML" : "JSON")));

            MacCmsResponse response = macCmsApiClient.getList(site.getSiteUrl(), request, site.getDataFormat());
            if (response == null) {
                return "连接站点失败";
            }

            StringBuilder result = new StringBuilder();
            result.append("连接成功!\n");
            if (response.getPage() != null) {
                result.append("总记录数: ").append(response.getPage().getRecordcount()).append("\n");
            }
            if (response.getList() != null) {
                result.append("获取到 ").append(response.getList().size()).append(" 条数据\n");
                for (int i = 0; i < Math.min(3, response.getList().size()); i++) {
                    MacCmsResponse.VodInfo vod = response.getList().get(i);
                    result.append("- ").append(vod.getVodName()).append("\n");
                }
            }

            return result.toString();
        } catch (Exception e) {
            return "测试失败: " + e.getMessage();
        }
    }

    /**
     * 【优化】批量查询已存在的影视
     *
     * @param vodList 视频列表
     * @param siteFlag 站点标识
     * @return Map<采集ID, MovieBasics>
     */
    private Map<String, MovieBasics> batchQueryExistingMovies(List<MacCmsResponse.VodInfo> vodList, String siteFlag) {
        if (vodList == null || vodList.isEmpty()) {
            return new HashMap<>();
        }

        // 提取所有采集ID
        List<String> collectIds = vodList.stream()
            .map(vod -> vod.getVodId())
            .collect(Collectors.toList());

        // 批量查询（假设有批量查询方法，如果没有需要添加）
        List<MovieBasics> existingList = movieBasicsService.selectMoviesByCollectIds(collectIds,siteFlag);

        // 构建Map
        Map<String, MovieBasics> resultMap = new HashMap<>();
        if (existingList != null) {
            for (MovieBasics movie : existingList) {
                if (movie.getCollectId() != null) {
                    resultMap.put(movie.getCollectId(), movie);
                }
            }
        }

        log.debug("批量查询完成，当前页{}个视频，已存在{}个", vodList.size(), resultMap.size());
        return resultMap;
    }

    /**
     * 【优化】准备视频数据（不直接操作数据库）
     *
     * @param vod 远程视频信息
     * @param site 采集站点
     * @param task 采集任务
     * @param bindMap 类型绑定映射
     * @param existingMoviesMap 已存在的影视映射
     * @return 处理结果
     */
    private ProcessResult prepareVodData(MacCmsResponse.VodInfo vod, CollectSite site, CollectTask task,
                                         Map<String, CollectBind> bindMap,
                                         Map<String, MovieBasics> existingMoviesMap) {
        // 转换为MovieBasics
        MovieBasics movie = dataTransformer.transformToMovieBasics(vod, task, bindMap);

        // 数据验证
        if (!dataDeduplicator.isValidMovie(movie)) {
            log.warn("无效的影视数据，跳过: {}", movie.getTitle());
            return new ProcessResult(true);
        }

        // 图片本地化处理（耗时操作，保留）
        if ("1".equals(site.getPicMode()) && StringUtils.isNotEmpty(movie.getPoster())) {
            String localPath = imageLocalizer.downloadImage(movie.getPoster());
            movie.setPoster(localPath);
        }

        // 从缓存Map中检查是否存在
        String collectId = vod.getVodId();
        MovieBasics existing = existingMoviesMap.get(collectId);

        if (existing != null) {
            // 检查是否需要更新
            if (dataTransformer.needsUpdate(existing, vod, site.getUprule())) {
                dataTransformer.mergeMovieData(existing, movie, site.getUprule());

                // 准备视频资源
                List<VideoResource> resources = prepareVideoResourcesForUpdate(
                    existing.getMovieBasicsId(), vod, site.getUprule());

                return new ProcessResult(existing, resources, false);
            } else {
                // 不需要更新，跳过
                return new ProcessResult(true);
            }
        } else {
            // 新影视，但还需要检查去重
            MovieBasics duplicate = findDuplicateMovieQuick(movie);
            if (duplicate != null) {
                log.info("发现重复影视: {} (ID: {}), 跳过采集", movie.getTitle(), duplicate.getMovieBasicsId());
                return new ProcessResult(true);
            }

            // 准备视频资源
            List<VideoResource> resources = dataTransformer.transformToVideoResources(
                vod, null); // movieId稍后批量设置

            return new ProcessResult(movie, resources, true);
        }
    }

    /**
     * 准备更新的视频资源
     */
    private List<VideoResource> prepareVideoResourcesForUpdate(Integer movieId,
                                                                MacCmsResponse.VodInfo vod,
                                                                String uprule) {
        List<VideoResource> newResources = dataTransformer.transformToVideoResources(vod, movieId);
        // 注意：这里简化处理，完整的合并逻辑可能需要查询现有资源
        // 但为了性能，我们直接返回新资源，由batchSaveMovies统一处理
        return newResources;
    }

    /**
     * 快速查找重复影视（使用缓存优化）
     */
    private MovieBasics findDuplicateMovieQuick(MovieBasics movie) {
        // 简化版本：只根据标题+年份查询
        MovieBasics query = new MovieBasics();
        query.setTitle(movie.getTitle());
        query.setYear(movie.getYear());
        query.setCollectFrom(movie.getCollectFrom());
        List<MovieBasics> candidates = movieBasicsService.selectMovieBasicsList(query);

        if (candidates != null && !candidates.isEmpty()) {
            for (MovieBasics candidate : candidates) {
                if (dataDeduplicator.isDuplicate(movie, candidate)) {
                    return candidate;
                }
            }
        }
        return null;
    }

    /**
     * 【优化】批量保存影视数据
     *
     * @param processResults 处理结果列表
     * @return 成功数量
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchSaveMovies(List<ProcessResult> processResults) {
        if (processResults == null || processResults.isEmpty()) {
            return 0;
        }

        int successCount = 0;
        List<MovieBasics> toInsert = new ArrayList<>();
        List<MovieBasics> toUpdate = new ArrayList<>();
        List<VideoResource> allResources = new ArrayList<>();

        // 【优化】收集所有数据字典
        DictionaryCollector dictionaryCollector = new DictionaryCollector();

        // 分类收集
        for (ProcessResult result : processResults) {
            if (result.isNew) {
                toInsert.add(result.movie);
            } else {
                toUpdate.add(result.movie);
                // 更新的视频需要先删除旧资源
                if (result.movie.getMovieBasicsId() != null && result.resources != null) {
                    videoResourceService.deleteVideoResourceListByMovieId(result.movie.getMovieBasicsId());
                }
            }

            // 【优化】收集数据字典（延迟保存）
            dictionaryCollector.collect(result.movie);
        }

        // 批量插入新影视
        if (!toInsert.isEmpty()) {
            log.info("批量插入{}部新影视", toInsert.size());
            for (MovieBasics movie : toInsert) {
                try {
                    movieBasicsService.insertMovieBasics(movie);
                    successCount++;

                    // 找到对应的资源并设置movieId
                    for (ProcessResult result : processResults) {
                        if (result.isNew && result.movie == movie && result.resources != null) {
                            for (VideoResource resource : result.resources) {
                                resource.setMovieId(movie.getMovieBasicsId());
                            }
                            allResources.addAll(result.resources);
                        }
                    }
                } catch (Exception e) {
                    log.error("插入影视失败: {}, 错误: {}", movie.getTitle(), e.getMessage());
                }
            }
        }

        // 批量更新影视
        if (!toUpdate.isEmpty()) {
            log.info("批量更新{}部影视", toUpdate.size());
            for (MovieBasics movie : toUpdate) {
                try {
                    movieBasicsService.updateMovieBasics(movie);
                    successCount++;

                    // 收集更新影视的资源
                    for (ProcessResult result : processResults) {
                        if (!result.isNew && result.movie == movie && result.resources != null) {
                            allResources.addAll(result.resources);
                        }
                    }
                } catch (Exception e) {
                    log.error("更新影视失败: {}, 错误: {}", movie.getTitle(), e.getMessage());
                }
            }
        }

        // 批量插入所有视频资源
        if (!allResources.isEmpty()) {
            log.info("批量插入{}条视频资源", allResources.size());
            try {
                videoResourceService.batchInsertVideoResource(allResources);
            } catch (Exception e) {
                log.error("批量插入视频资源失败: {}", e.getMessage());
            }
        }

        // 【优化】批量保存所有数据字典
        dictionaryCollector.saveBatch(dataDictionaryService);

        return successCount;
    }

    /**
     * 数据字典收集器（用于批量保存）
     */
    private static class DictionaryCollector {
        private final java.util.Set<String> countries = new java.util.HashSet<>();
        private final java.util.Set<String> actors = new java.util.HashSet<>();
        private final java.util.Set<String> directors = new java.util.HashSet<>();
        private final java.util.Set<String> writers = new java.util.HashSet<>();
        private final java.util.Set<String> languages = new java.util.HashSet<>();

        /**
         * 收集一个影视的所有数据字典
         */
        void collect(MovieBasics movie) {
            if (movie == null) {
                return;
            }

            // 收集国家/地区
            if (StringUtils.isNotEmpty(movie.getArea())) {
                countries.addAll(parseText(movie.getArea()));
            }

            // 收集演员
            if (StringUtils.isNotEmpty(movie.getActorText())) {
                actors.addAll(parseText(movie.getActorText()));
            }

            // 收集导演
            if (StringUtils.isNotEmpty(movie.getDirectorText())) {
                directors.addAll(parseText(movie.getDirectorText()));
            }

            // 收集编剧
            if (StringUtils.isNotEmpty(movie.getWriterText())) {
                writers.addAll(parseText(movie.getWriterText()));
            }

            // 收集语言
            if (StringUtils.isNotEmpty(movie.getLanguages())) {
                languages.addAll(parseText(movie.getLanguages()));
            }
        }

        /**
         * 批量保存所有收集的数据字典
         */
        void saveBatch(IDataDictionaryService service) {
            if (!countries.isEmpty()) {
                log.info("批量保存{}个国家/地区", countries.size());
                service.batchSaveCountries(new ArrayList<>(countries));
            }

            if (!actors.isEmpty()) {
                log.info("批量保存{}个演员", actors.size());
                service.batchSaveActors(new ArrayList<>(actors));
            }

            if (!directors.isEmpty()) {
                log.info("批量保存{}个导演", directors.size());
                service.batchSaveDirectors(new ArrayList<>(directors));
            }

            if (!writers.isEmpty()) {
                log.info("批量保存{}个编剧", writers.size());
                service.batchSaveWriters(new ArrayList<>(writers));
            }

            if (!languages.isEmpty()) {
                log.info("批量保存{}个语言", languages.size());
                service.batchSaveLanguages(new ArrayList<>(languages));
            }
        }

        /**
         * 解析逗号分隔的文本
         */
        private static List<String> parseText(String text) {
            if (StringUtils.isEmpty(text)) {
                return new ArrayList<>();
            }

            return Arrays.stream(text.split("[,，]"))
                    .map(String::trim)
                    .filter(StringUtils::isNotEmpty)
                    .distinct()
                    .collect(java.util.stream.Collectors.toList());
        }
    }
}
